package com.topisv.tms.service.stock.preinstorage;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.QueryParamHolder;
import com.topisv.tms.entity.edb.EdbInOutStore;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountItem;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillBoxPre;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillItemPre;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillPre;
import com.topisv.tms.entity.stock.instorage.pre.PreInBill;
import com.topisv.tms.entity.task.MdSendOutTask;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.edb.EdbInOutStoreDao;
import com.topisv.tms.repository.stock.instorage.InstorageBillDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountItemDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillBoxPreDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillItemPreDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillPreDao;
import com.topisv.tms.repository.task.MdSendOutTaskDao;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.utils.enums.InstorageNewStatusEnums;
import com.topisv.tms.utils.enums.InstorageStatusEnums;
import com.topisv.tms.utils.enums.MDGoodsStatus;
import com.topisv.tms.utils.enums.MDOrderType;
import com.topisv.tms.utils.enums.PYOrderType;
import com.topisv.tms.utils.enums.StatusEnums;
//import com.topisv.tms.utils.http.SynchroShippedBatchQueue;
import com.topisv.tms.utils.rule.TMSTransportRule;
import com.topisv.tms.utils.vo.PreInstorageVo;

/**
 * 预约入库Service
 *  Date          Author       Version       Description
 * ----------------------------------------------------------
 *  2014-7-3      CC            1.0           Create
 */
@Component
@Transactional(readOnly = true)
public class PreInstorageService extends BaseService {
	@Autowired
	private InstorageBillPreDao instorageBillPreDao;
	@Autowired
	private InstorageBillBoxPreDao instorageBillBoxPreDao;
	@Autowired
	private InstorageBillItemPreDao instorageBillItemPreDao;
	@Autowired
	private InstorageBillDao instorageBillDao;
	@Autowired
	private InstorageCountItemDao instorageCountItemDao;
	@Autowired
	private MdSendOutTaskDao mdSendOutTaskDao;
	@Autowired
	private EdbInOutStoreDao edbInOutStoreDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
	private JdbcTemplate jdbcTemplate;
	/**
	 * 保存预约入库信息
	 * @param preInstorageVo
	 * @throws Exception 
	 */
	@Transactional(readOnly = false)
	public InstorageBillPre saveInstorageBillPre(PreInstorageVo preInstorageVo, String billType) throws Exception {
		Long id = null;
		if ((id = preInstorageVo.getInstorageBillPre().getId()) != null) {
			deletePreInstorageInfo(id);
		}
		countSku(preInstorageVo);
		InstorageBillPre instorageBillPre = preInstorageVo.getInstorageBillPre();
		List<InstorageBillBoxPre> boxes = preInstorageVo.getInstorageBillBoxPres();
		List<InstorageBillItemPre> itemPres = preInstorageVo.getInstorageBillItemPres();
		//instorageBillPre.setBillType(billType);
		// 预约单号编码规则：'PRE'+时间,例如：PRE201309091212004
		if (StatusEnums.PREORDER_STATUS_SEND.getStatus().equals(instorageBillPre.getOrderStatus())) {
			instorageBillPre.setBillCode(TMSTransportRule.generatePreStorageBillCode());
			// 已发货则保存到正式表
			saveInstorageInfo(preInstorageVo, billType);
		}
		instorageBillPreDao.save(instorageBillPre);
		if (boxes != null) {
			for (InstorageBillBoxPre instorageBillBoxPre : boxes) {
				instorageBillBoxPre.setBillPreId(instorageBillPre.getId());
			}
		}
		if (null != itemPres) {
			for(int i = 0;i<itemPres.size();i++){
				if(StringUtils.isNotBlank(itemPres.get(i).getSkuCode())){
					itemPres.get(i).setBillPreId(instorageBillPre.getId());
				}else{
					itemPres.remove(i) ;
					i-- ;
					instorageBillPre.setSkuNum(instorageBillPre.getSkuNum()-1);
				}
			}
		}
		instorageBillBoxPreDao.save(boxes);
		instorageBillItemPreDao.save(itemPres);
		// 通知邮件发送
		if (StatusEnums.PREORDER_STATUS_SEND.getStatus().equals(instorageBillPre.getOrderStatus())) {
//			SynchroShippedBatchQueue.putPreBillMail(preInstorageVo);
		}
		return instorageBillPre;
	}
	
	/**
	 * 保存预约入库信息
	 * @param preInstorageVo
	 * @throws Exception 
	 */
	@Transactional(readOnly = false)
	public void saveInstorageBillPre(PreInstorageVo preInstorageVo) throws Exception {
		saveInstorageBillPre(preInstorageVo, PYOrderType.PRE_ORDER.getType());
	}

	private void countSku(PreInstorageVo preInstorageVo) {
		Date now = new Date();
		InstorageBillPre instorageBillPre = preInstorageVo.getInstorageBillPre();
		instorageBillPre.setId(null);
		instorageBillPre.setCreateTm(now);
		instorageBillPre.setCreateCode(getShiroUser() == null ? "SYSTEM" : getShiroUser().realname);
		List<InstorageBillBoxPre> boxes = preInstorageVo.getInstorageBillBoxPres();
		List<InstorageBillItemPre> itemPres = preInstorageVo.getInstorageBillItemPres();
		instorageBillPre.setBoxNum(boxes != null ? boxes.size() : 0);
		Integer totalSkuNum = 0;
		Integer totalGoodsNum = 0;
		if (boxes != null) {
			if (itemPres != null) {
				for (InstorageBillItemPre instorageBillItemPre : itemPres) {
					if(StringUtils.isNotBlank(instorageBillItemPre.getSkuCode())){
						totalSkuNum++;
						totalGoodsNum += instorageBillItemPre.getGoodsNum() == null ? 0 : instorageBillItemPre.getGoodsNum();
					}
				}
			}
		}
		instorageBillPre.setSkuNum(totalSkuNum);
		instorageBillPre.setGoodsNum(totalGoodsNum);
	}

	@Transactional(readOnly = false)
	public void saveInstorageBillPre4MD(PreInstorageVo preInstorageVo, MDOrderType orderType) throws Exception {
		if (orderType == MDOrderType.PURCHASE) {// 预约类型
			saveInstorageBillPre(preInstorageVo);
		} else if (orderType == MDOrderType.RETURN) {// 退回类型
			saveInstorageBillPre(preInstorageVo, PYOrderType.RETURN_ORDER.getType());
		}
		// 生成处理任务
		MdSendOutTask task = new MdSendOutTask();
		task.setCrTime(new Date());
		task.setDealStatus("0");
		task.setCustomerOrderNo(preInstorageVo.getInstorageBillPre().getCustomerOrderNo());
		task.setWorkNum(1);
		task.setDoneNum(0);
		task.setDealCount(0);
		task.setOrderType(orderType.getType());
		mdSendOutTaskDao.save(task);
	}
	
	@Transactional(readOnly = false)
	public void saveInstorageBillPreEdb(PreInstorageVo preInstorageVo) throws Exception {
		
		saveInstorageBillPre(preInstorageVo);
		
		// 生成处理任务
		EdbInOutStore edbStore = new EdbInOutStore();
		edbStore.setCreateTime(new Date());
		edbStore.setStatus("0");
		edbStore.setOrderType("01");
		edbStore.setTid(preInstorageVo.getInstorageBillPre().getCustomerOrderNo());
		edbStore.setCustomerCode(preInstorageVo.getInstorageBillPre().getCustomerCode());
		edbStore.setWhcode(preInstorageVo.getInstorageBillPre().getInwarehouseCode());
		edbStore.setBillCode(preInstorageVo.getInstorageBillPre().getBillCode());
		edbInOutStoreDao.save(edbStore);
		
	}
	
	@Transactional(readOnly = false)
	public void saveInstorageBillPreLMB(PreInstorageVo preInstorageVo) throws Exception {
		InstorageBillPre instorageBillPre = instorageBillPreDao.findByCustomerCodeAndCustomerOrderNo2(preInstorageVo.getInstorageBillPre().getCustomerCode()
				,preInstorageVo.getInstorageBillPre().getCustomerOrderNo());
		if(null == instorageBillPre)
		{
			saveInstorageBillPre(preInstorageVo,preInstorageVo.getInstorageBillPre().getBillType());
		}
		
	}

	/**
	 * 将数据保存到正式表
	 * @param preInstorageVo
	 * @throws Exception 
	 */
	@Transactional(readOnly = false)
	public void saveInstorageInfo(PreInstorageVo preInstorageVo, String billType) throws Exception {
		InstorageBillPre preBill = preInstorageVo.getInstorageBillPre();
		InstorageBill bill = new InstorageBill();
		Date now = new Date();
		// 入库单类型 (1.采购入库 2.调拨入库 )
		bill.setBillType(billType);
		// 入库单号
		bill.setBillCode(TMSTransportRule.generateInStorageBillCode());
		// 商户信息
		bill.setCustomerCode(preBill.getCustomerCode());
		// 入库仓库信息
		bill.setInwarehouseCode(preBill.getInwarehouseCode());
		// 箱子数量
		bill.setBoxNum(preBill.getBoxNum());
		// SKU数量
		bill.setSkuNum(preBill.getSkuNum());
		// 商品数量
		bill.setGoodsNum(preBill.getGoodsNum());
		// 备注
		bill.setRemarks(preBill.getRemark());
		// 创建人
		bill.setCreaterUuid(getShiroUser() == null ? "SYSTEM" : getShiroUser().jobuuid);
		// 入库时间
		bill.setCreateTime(now);
		// 入库状态 （ -1代表走边收货边上架流程 0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
		bill.setStatus("0");
		// 是否破损件
		bill.setErrorFlag(MDGoodsStatus.OTHERS.getType().equals(preBill.getErrorFlg()) ? "error" : "noterror");
		// 相关单号
		bill.setAboutCode(preBill.getBillCode());
		// 入库单号
		//preBill.setInBillCode(bill.getBillCode());
		//二次收货标志
		bill.setUpdateFlag("0");
		// 边收边上架状态 -1代表不走边收货边上架流程 0：新建 1:部分收货未上架  2:部分收货部分上架 3:部分收货完全上架 4:完全收货未上架 5:完全收货部分上架 6:完全收货完全上架 7:已关闭 8:已取消
		bill.setNewstatus("0");
		
		// 标记订单是否可以取消 419 yuangsheng
		// 是否可以取消
		if (preInstorageVo.getManuelFlag() == 1) {
            bill.setCancelFlag(1);
        }
		// 标记订单是否可以取消 419 yuangsheng
		
		PreInBill preInBill = new PreInBill();
		preInBill.setInBillCode(bill.getBillCode());
		preBill.setPreInBills(Arrays.asList(preInBill));
		instorageBillDao.save(bill);
	}

	/**
	 * 删除预约信息
	 * @param id
	 */
	@Transactional(readOnly = false)
	public void deletePreInstorageInfo(Long id) {
		instorageBillPreDao.delete(id);
		instorageBillBoxPreDao.deleteInstorageBillBoxPre(id);
		instorageBillItemPreDao.deleteInstorageBillItemPre(id);
	}

	/**
	 * 查询预约信息
	 * @param id
	 * @return
	 */
	public PreInstorageVo queryPreInstorageVo(String id) {
		Long i = Long.valueOf(id);
		return queryPreInstorageVo(i);
	}

	/**
	 * 查询预约信息
	 * @param id
	 * @return
	 */
	public PreInstorageVo queryPreInstorageVo(Long i) {
		PreInstorageVo vo = new PreInstorageVo();
		InstorageBillPre instorageBillPre = instorageBillPreDao.findOne(i);
		vo.setInstorageBillPre(instorageBillPre);
		vo.setInstorageBillBoxPres(instorageBillBoxPreDao.query(i));
		
		List<InstorageBillItemPre> items = instorageBillItemPreDao.query(i);
		for (InstorageBillItemPre instorageBillItemPre : items) {
			EdiGoodsSku goodsSku = ediGoodsSkuDao.findByCustomerCodeAndSku(instorageBillPre.getCustomerCode(), instorageBillItemPre.getSkuCode());
			if (goodsSku != null) {
				instorageBillItemPre.setSkuBar(goodsSku.getSkuName());
			}
		}
		vo.setInstorageBillItemPres(items);
		return vo;
	}

	/**
	 * 查看预约信息
	 * @param params
	 * @param pageNumber
	 * @param fromDate
	 * @param toDate
	 * @return
	 */
	public Page<InstorageBillPre> queryInstorageBillPre(Map<String, Object> params, int pageNumber, int pageSize, Date fromDate, Date toDate) {
		return instorageBillPreDao.findAll(buildSpecification(params, fromDate, toDate, InstorageBillPre.class), buildPageRequest(pageNumber, pageSize));
	}

	public Page<InstorageBillPre> queryInstorageBillPre(QueryParamHolder paramHolder) {
		return findByJson(paramHolder, instorageBillPreDao, InstorageBillPre.class);
	}

	/**
	 * 查找点收明细
	 * @param billCode
	 * @return List<InstorageCountItem>
	 */
	public List<InstorageCountItem> queryInstorageCountItem(String billCode) {
		return instorageCountItemDao.loadByBillCode(billCode);
	}

	private <T> Specification<T> buildSpecification(Map<String, Object> filterParams, Date fromDate, Date endDate, Class<T> clazz) {
		Map<String, SearchFilter> filters = SearchFilter.parse(filterParams);
		if (fromDate != null) {
			filters.put("fromDate", new SearchFilter("createTm", Operator.GTE, fromDate));
		}
		if (endDate != null) {
			filters.put("toDate", new SearchFilter("createTm", Operator.LT, endDate));
		}
		return DynamicSpecifications.bySearchFilter(filters.values(), clazz);
	}

	private PageRequest buildPageRequest(int pageNumber, int pageSize) {
		String[] sorts = { "id" };
		Sort sort = new Sort(Direction.DESC, sorts);
		return new PageRequest(pageNumber - 1, pageSize, sort);
	}

	public InstorageBillPre findByInBillCode(String inBillCode) {
		return instorageBillPreDao.findByInBillCode(inBillCode);
	}
	
	public InstorageBillPre findByBillCode(String inBillCode) {
		return instorageBillPreDao.findByBillCode(inBillCode);
	}

	/**
	 * 取消入库单
	 */
	@Transactional(readOnly = false)
	public void cancelPreOrderByCusNo(String customerOrderNo, String customerCode) throws Exception {
		InstorageBillPre billPre = instorageBillPreDao.findByCustomerCodeAndCustomerOrderNo(customerCode, customerOrderNo);
		if (billPre == null) {
			throw new PaiUException(ErrorCode.ORDER_NOTFOUND_ERROR, new String[] { customerOrderNo });
		}
		// 已上架 不允许取消
		if (StatusEnums.PREORDER_STATUS_CHECK.getStatus().equals(billPre.getOrderStatus())) {
			throw new PaiUException(ErrorCode.ORDER_UPED_ERROR, new String[] { customerOrderNo });
		}
		// 已取消的,返回true
		if (StatusEnums.PREORDER_STATUS_CANEL.getStatus().equals(billPre.getOrderStatus())) {
			return;
		}
		List<PreInBill> preInBills = billPre.getPreInBills();
		for (PreInBill preInBill : preInBills) {
			// 查看入库单状态
			InstorageBill instorageBill = instorageBillDao.loadBillByCode(preInBill.getInBillCode());
			if (instorageBill == null) {
				billPre.setOrderStatus(StatusEnums.PREORDER_STATUS_CANEL.getStatus());
				return;
			}
			if (!(InstorageStatusEnums.NOT.getType().equals(instorageBill.getStatus()))) {
				// 已上架 不允许取消
				if (InstorageStatusEnums.UPED.getType().equals(instorageBill.getStatus())) {
					throw new PaiUException(ErrorCode.ORDER_UPED_ERROR, new String[] { customerOrderNo });
				}
				// 已取消的,返回true
				if (InstorageStatusEnums.CANCEL.getType().equals(instorageBill.getStatus())) {
					return;
				}
			}else{//边收边上架
				log.info("边收边上架，取消入库单!"+instorageBill.getNewstatus());
				// 已上架 不允许取消
				if (Integer.valueOf(instorageBill.getNewstatus())>Integer.valueOf(InstorageNewStatusEnums.CREATENEW.getType())&&Integer.valueOf(instorageBill.getNewstatus())<Integer.valueOf(InstorageNewStatusEnums.CANCLE.getType())) {
					throw new PaiUException(ErrorCode.ORDER_UPED_ERROR, new String[] { customerOrderNo });
				}
				// 已取消的,返回true
				if (InstorageNewStatusEnums.CANCLE.getType().equals(instorageBill.getNewstatus())) {
					return;
				}
			}
			
			billPre.setOrderStatus(StatusEnums.PREORDER_STATUS_CANEL.getStatus());
			if(InstorageStatusEnums.NOT.getType().equals(instorageBill.getStatus())){
				instorageBill.setNewstatus(InstorageNewStatusEnums.CANCLE.getType());
			}else if(InstorageNewStatusEnums.NOTNEW.getType().equals(instorageBill.getNewstatus())){
				instorageBill.setStatus(InstorageStatusEnums.CANCEL.getType());
			}else if(InstorageNewStatusEnums.CREATENEW.getType().equals(instorageBill.getNewstatus()) &&InstorageStatusEnums.WAIT.getType().equals(instorageBill.getStatus())){
				instorageBill.setStatus(InstorageStatusEnums.CANCEL.getType());
				instorageBill.setNewstatus(InstorageNewStatusEnums.CANCLE.getType());
			}
			log.info("边收边上架，取消入库单!instorageBill:"+instorageBill);
			instorageBillDao.save(instorageBill);
			instorageBillPreDao.save(billPre);
		}
	}
	
	public List<InstorageBillItemPre> fiindByBillPreId(Long billPreId){
		return instorageBillItemPreDao.findByPreidAndError(billPreId);
	}
	
	public List<InstorageBillPre> findByWhere(Map<String, Object> param){
		Specification<InstorageBillPre> spec = getWhereClause(param);
		List<InstorageBillPre> list = instorageBillPreDao.findAll(spec);
		return list;
	}
	
private Specification<InstorageBillPre> getWhereClause(final Map<String, Object> searchParams) {
		
		return new Specification<InstorageBillPre>(){
			
		    @Override
		    public Predicate toPredicate(Root<InstorageBillPre> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		      String customerCode=(String) searchParams.get("customerCode");
		      if(StringUtils.isNotBlank(customerCode)){
					pre.getExpressions().add(cb.equal(r.get("customerCode"),customerCode.trim()));
			  }
		      
		      String warehouseCode=(String) searchParams.get("warehouseCode");
		      if(StringUtils.isNotBlank(warehouseCode)){
					pre.getExpressions().add(cb.equal(r.get("inwarehouseCode"),warehouseCode.trim()));
			  }
		      
		      String orderStatus=(String) searchParams.get("orderStatus");
		      if(StringUtils.isNotBlank(orderStatus)){
					pre.getExpressions().add(cb.equal(r.get("orderStatus"),orderStatus.trim()));
			  }

		      Date fromDate= (Date) searchParams.get("fromDate");
		      if (fromDate != null) {
		        pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date>get("createTm"), fromDate));
		      }
		      
		      Date toDate= (Date) searchParams.get("toDate");
		      if (toDate != null) {
		        pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date>get("createTm"), toDate));
		      }
		      return pre;
		    }
		  };
       }
	
	public List<InstorageBillItemPre> findBillItemPreById(Long id){
		return instorageBillItemPreDao.query(id);
	}
	public InstorageBillPre findByCustomerCodeAndCustomerOrderNo2(String customerCode,String customerOrderNo){
		return instorageBillPreDao.findByCustomerCodeAndCustomerOrderNo2(customerCode, customerOrderNo) ;
	}
	public List<Map<String,Object>> getInstorageBillItemPreList(Long id){
		String sql="select a.sku_name as skuName,a.spec as spec,b.about_code as aboutCode,b.create_time as createTime,"
				    + "b.inwarehouse_code as warehouseCode,b.customer_code as customerCode,b.bill_code as billCode, b.sku_code as skuCode,b.goods_num as goodsNum from edi_goods_sku a ,"
					+ "(" 
					+ "select a.about_code,date_format(a.create_time,'%Y-%m-%d %H:%I:%S') as create_time ,a.inwarehouse_code,a.customer_code,a.bill_code,c.sku_code,c.goods_num from instorage_bill a,instorage_bill_pre b,instorage_bill_item_pre c "
					+ "where a.about_code=b.bill_code and b.id=c.bill_pre_id and c.bill_pre_id="+id
					+ ") b" 
					+ " where a.customer_code=b.customer_code and a.sku_id=b.sku_code ";
		return jdbcTemplate.queryForList(sql);
	}
	public int updateInstorageBillPrintNum(String billCode){
		String sql="update instorage_bill set print_num=print_num+1 where about_code='"+billCode+"'";
		return jdbcTemplate.update(sql);
	}
}
